#include "matlab_interface2.hpp"
#include <string>
#include <iostream>
#include <memory>
#include <Windows.h>
#include <filesystem>
#include <fstream>
#include "nlohmann/json.hpp"
using json = nlohmann::json;
using namespace std;
using namespace cv;
namespace fs = std::filesystem;
std::string findJson(const std::string &json) {
    for (auto i: {"./", "./../resource", "./resource"}) {
        if (fs::exists(i))
            for (auto const &dir_entry: fs::directory_iterator{i}) {
                if ((!dir_entry.is_directory()) &&
                    (dir_entry.path().filename() == json)) {
                    return dir_entry.path().string();
                }
            }
    }
    return "";
}
vector<string> dll_files;
vector<string> json_files;
std::vector<HINSTANCE> plugin_dll_handles;//析构时记得用FreeLibrary释放
std::vector<cpp_plugin::interface_t *> *get_cpp_plugin_instance_lists(void) {
    //清空变量
    dll_files.clear();
    plugin_dll_handles.clear();

    //加载matlab会话
    const char *args[] = {"-nojvm"};
    const int count = sizeof(args) / sizeof(args[0]);
    mclInitializeApplication(args, count);

    auto *rtv = new std::vector<cpp_plugin::interface_t *>();
    //扫描matlab导出的dll
    for (auto i: {"./", "./../plugin", "./plugin"}) {
        if (fs::exists(i))
            for (auto const &dir_entry: fs::directory_iterator{i}) {
                if ((!dir_entry.is_directory()) &&
                    (dir_entry.path().string().find(".dll") != string::npos)) {
                    dll_files.push_back(dir_entry.path().string());
                    cout << dir_entry.path().string() << endl;
                }
            }
    }
    //创建对象
    for (auto &i: dll_files) {
        auto file_name = fs::path(i).filename().string();
        file_name = file_name.substr(0, file_name.rfind('.'));
        HINSTANCE hDll = LoadLibrary(i.c_str());// 加载DLL库文件
        if (hDll == nullptr)
            continue;
        auto *initialize = (matlab_interface_t::Init_t) GetProcAddress(hDll, (file_name + "Initialize").c_str());
        auto *terminate = (matlab_interface_t::Termi_t) GetProcAddress(hDll, (file_name + "Terminate").c_str());
        auto *run = (matlab_interface_t::Run_t) GetProcAddress(hDll, (LPCSTR) (0x1));
        auto file = findJson(fs::path(i).filename().stem().string() + ".json");
        if (initialize == nullptr || terminate == nullptr || run == nullptr || file.empty()) {
            FreeLibrary(hDll);
            continue;
        }

        ifstream jsonfile(file);
        json j;
        if (jsonfile.is_open()) jsonfile >> j;
        if (
                j.at("name").is_null() ||
                j.at("help_info").is_null() ||
                j.at("icon").is_null() ||
                j.at("arg").is_null() ||
                j.at("arg_default").is_null() ||
                j.at("arg_min").is_null() ||
                j.at("arg_max").is_null() ||
                j.at("pre_view").is_null()
                ) {
            FreeLibrary(hDll);
            continue;
        }
        plugin_dll_handles.push_back(hDll);

        rtv->push_back(new matlab_interface_t(
                initialize, terminate, run,
                j.at("name"), j.at("help_info"), j.dump()));
    }
    return rtv;
}


void get_cpp_plugin_instance_deletor(std::vector<cpp_plugin::interface_t *> *instance) {
    for (auto &i: *instance) {
        delete i;
    }

    delete instance;

    for (auto i: plugin_dll_handles) {
        FreeLibrary(i);
    }
    mclTerminateApplication();

    //清空变量
    dll_files.clear();
    plugin_dll_handles.clear();
}